package com.wang.lotterysystem.dao.handler;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.AES;
import com.wang.lotterysystem.dao.dataobject.Encrypt;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.nio.charset.StandardCharsets;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * MyBatis取出和放入数据时对数据进行自动加密和解密
 */
@MappedTypes(Encrypt.class)  //原本的数据类型
@MappedJdbcTypes(JdbcType.VARCHAR  )//sql中的数据类型
public class EncryptTypeHandler extends BaseTypeHandler<Encrypt> {

    //对手机号使用对称加密
    private static byte[] KEY = "123456789abcdefg".getBytes(StandardCharsets.UTF_8);

    /**
     * 参数设置(加密并设置对象)
     * @param ps sql预编译对象
     * @param i 需要赋值的索引位置
     * @param parameter 原本位置i需要赋的值
     * @param jdbcType JDBC类型数据
     * @throws SQLException
     */
    @Override
    public void setNonNullParameter(PreparedStatement ps, int i, Encrypt parameter, JdbcType jdbcType) throws SQLException {
        //添加的数据为空
        if (parameter == null || parameter.getValue() == null){
            ps.setString(i,null);//由于数据库中对应的是varchar数据类型,所以这里使用的是setString方法,即对应java中的String类型
            return;
        }
        //对数据进行加密之后放入数据库中
        AES aes = SecureUtil.aes(KEY);//设置密钥
        String encrypted = aes.encryptHex(parameter.getValue());//对数据进行加密
        ps.setString(i,encrypted);//把数据放入数据库的预编译对象中
    }

    /**
     *
     * @param rs 结果集
     * @param columnName 索引名
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, String columnName) throws SQLException {
        return decrypt(rs.getString(columnName));//从指定的索引中获取加密对象之后解密
    }

    /**
     *
     * @param rs 结果集
     * @param columnIndex 索引名
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
        return decrypt(rs.getString(columnIndex));
    }

    /**
     *
     * @param cs 结果集
     * @param columnIndex 索引名
     * @return
     * @throws SQLException
     */
    @Override
    public Encrypt getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
        return decrypt(cs.getString(columnIndex));
    }

    /**
     * 解密
     * @return 返回解密后的对象
     */
    private Encrypt decrypt(String value){
        if (value == null){
            return null;
        }
        return new Encrypt(SecureUtil.aes(KEY).decryptStr(value));
    }
}